package com.cctc.juc.source.Athread.threadpool;

import java.util.concurrent.*;

import static java.util.concurrent.TimeUnit.NANOSECONDS;

/**
 * [ScheduledThreadPoolExecutor 可调度（周期性、延时）的线程池] 实现类
 * 描述信息：该类作为 [“可调度” 的线程池]（核心）实现类，可以实现定时（固定速率）| 定频（固定延迟）执行异步任务，该类比 Timer 更可取。
 * 面试题：ScheduledThreadPoolExecutor 与 Timer 的区别，为什么 ScheduledThreadPoolExecutor 比 Timer 更可取？
 * 技术演进（优化）路线：在 JDK 1.5 之前，实现任务的周期性、延时调度主要使用的是 Timer 和 TimerTask 类；从 JDK 1.5 开始，Java 提供了 ScheduledThreadPoolExecutor 和 ScheduledFutureTask 类，用于实现任务（周期性、延时）的调度。
 * 二者的区别：
 * 1. 任务调度线程层面
 * - Timer 内部的 TimerThread 继承自 Thread 类，为单线程模式，如果某个 TimerTask 任务长时间阻塞或出现异常，会影响到其他任务的调度执行；且 Timer 调度器是基于操作系统的绝对时间进行调度的，如果操作系统的时间发生改变，将无法再精确调度。
 * - ScheduledThreadPoolExecutor 是基于 ThreadPoolExecutor 线程池来实现任务调度的，某个 ScheduledFutureTask 任务的执行过程不会影响到其他任务的正常调度执行；且 ScheduledThreadPoolExecutor 调度器是基于相对时间进行调度的，不会因本机操作系统时间的改变而影响调度过程。
 * 2. 任务（按照优先级进行排序、捕获异常及获取结果）层面
 * 1）按照优先级进行排序：Timer 中执行的 TimerTask 任务只是实现了 Runnbale 接口，整体上没有优先级的概念，只能按照系统的绝对时间来执行任务；而 ScheduledThreadPoolExecutor 中执行的 ScheduledFutureTask 任务实现了 Delayed 和 Comparable 接口，可以按照下次调度执行的时间间隔大小进行排序，设置优先级别。
 * 2）抛出异常及返回结果：Timer 中执行的 TimerTask 任务只是实现了 Runnbale 接口，无法抛出异常，也无法返回结果，再加上 Timer 是单线程的，一旦某个任务出现异常，整个 Timer 线程就会终止，其他任务也都不会再被调度执行；而 ScheduledThreadPoolExecutor 中执行的 ScheduledFutureTask 继承自 FutureTask 类，可以抛出异常，也可以异步获取结果，再加上 ScheduledThreadPoolExecutor 是基于线程池来实现 ScheduledFutureTask 任务调度的，其中某个任务出现异常后，不会影响到其他任务的正常调度执行。
 */
public class GScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService {
    /**
     * [ScheduledFutureTask] “可调度的” 异步任务。
     * 描述信息：该类继承自 FutureTask（“增强版的” 异步任务），同时实现了 RunnableScheduledFuture 接口，合二为一，即为【“可调度的” 异步任务】。
     */
    private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> {
        // 任务序列号
        private final long sequenceNumber;
        // 延迟时间
        private long time;
        // 周期执行时间
        private final long period;
        // 任务实例
        RunnableScheduledFuture<V> outerTask = this;
        // 任务队列索引
        int heapIndex;

        ScheduledFutureTask(Callable<V> callable, long delay) {
            super(callable);
            this.sequenceNumber = sequencer.getAndIncrement();
            this.time = delay;
            this.period = 0;
        }


        @Override
        public boolean isPeriodic() {
            return period != 0;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(time - now(), NANOSECONDS);
        }

        @Override
        public int compareTo(Delayed other) {
            if (other == this) // compare zero if same object
                return 0;
            if (other instanceof ScheduledFutureTask) {
                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>) other;
                long diff = time - x.time;
                if (diff < 0)
                    return -1;
                else if (diff > 0)
                    return 1;
                else if (sequenceNumber < x.sequenceNumber)
                    return -1;
                else
                    return 1;
            }
            long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
        }
    }

    /**
     * [核心] 构造器
     *
     * @param corePoolSize  核心线程数
     * @param threadFactory 创建 Worker 工作线程的工厂
     * @default [默认配置]
     * - maximumPoolSize     最大线程数，没有数量限制（Integer.MAX_VALUE）；
     * - keepAliveTime       空闲线程存活时间，无期限（keepAliveTime = 0L）；
     * - workQueue          （阻塞）工作队列，无界（DelayedWorkQueue）；
     * - handler             拒绝策略，默认拒绝策略（AbortPolicy）。
     */
    public GScheduledThreadPoolExecutor(int corePoolSize,
                                        ThreadFactory threadFactory) {
        super(
                corePoolSize, Integer.MAX_VALUE,
                0, NANOSECONDS,
                new ScheduledThreadPoolExecutor.DelayedWorkQueue(),
                threadFactory
        );
    }

    // --- 创建 “可调度的” 线程池的 4 个 [核心] 方法 --- //

    @Override
    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
        /**
         * 按照提交顺序（FIFO）串行化（延迟）执行。
         * - 无返回值；
         * - 可以抛出异常信息，通过 ScheduledFuture 捕获异常。
         * 源码解析：将 Runnable 命令封装成 ScheduledFutureTask 任务，并通过 delayExecute() 方法来（延迟）执行，最后返回 ScheduledFuture 结果。
         */
        return null;
    }

    @Override
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
        /**
         * 按照提交顺序（FIFO）串行化（延迟）执行。
         * - 有返回值，通过 ScheduledFuture 获取结果；
         * - 可以抛出异常信息，通过 ScheduledFuture 捕获异常。
         * 源码解析：将 callable 命令封装成 ScheduledFutureTask 任务，并通过 delayExecute() 方法来（延迟）执行，最后返回 ScheduledFuture 结果。
         */
        return null;
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
        /**
         * 按照（定频）固定频率（period）延迟一定时间（initialDelay）后重复执行。
         * - 无返回值；
         * - 可以抛出异常信息，通过 ScheduledFuture 捕获异常。
         * 适用场景：需要周期性执行的任务，例如 SpringBoot 中的任务调度器底层使用的就是这个接口。
         * 源码解析：将 Runnable 命令封装成 ScheduledFutureTask 任务，并设置了执行周期（period），采用固定频率（上一次任务执行完成的时间 + period）来重复执行定时任务。
         */
        return null;
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
        /**
         * 按照（定时）固定延迟（delay）延迟一定时间（initialDelay）后重复执行。
         * - 有返回值，通过 ScheduledFuture 获取结果；
         * - 可以抛出异常信息，通过 ScheduledFuture 捕获异常。
         * 源码解析：将 Runnable 命令封装成 ScheduledFutureTask 任务，并设置了执行周期（delay），采用固定延迟（上一次任务执行完成的时间 + delay）来重复执行定时任务。
         */
        return null;
    }
}
